﻿//  Copyright (c) 2010 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Security;

namespace DNA.Mvc.UI
{
    public static class WidgetFounder
    {
        /// <summary>
        /// Detect the Widgets in assemblies then create the widget template to widget catalog.
        /// </summary>
        /// <param name="targetPath"></param>
        /// <param name="appPath"></param>
        /// <param name="webOwner"></param>
        /// <param name="descriptorRepository"></param>
        /// <param name="tmplRepository"></param>
        /// <param name="defaultCategory"></param>
        public static void Detect(string targetPath,
            string appPath,
            string areaPath,
            MembershipUser webOwner,
            IWidgetDescriptorRepository descriptorRepository,
            IWidgetTemplateRepository tmplRepository,
            string defaultCategory = "Shared")
        {
            //Auto detect package info
            string[] files = Directory.GetFiles(targetPath, "*.dll");

            foreach (string file in files)
            {
                try
                {
                    //When using LoadFile will cause could not get CustomAttributes!
                    Assembly assembly = Assembly.LoadFrom(file);
                    var attrs = assembly.GetCustomAttributes(true);
                    var fileInfo = new FileInfo(file);
                    var asmname = assembly.GetName();

                    Type[] types = assembly.GetTypes();

                    var controllers = types.Where(c => (c.BaseType == typeof(Controller) || c.BaseType == typeof(AsyncController)));

                    foreach (Type controller in controllers)
                    {
                        var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance);
                        var actions = methods.Where(m => (m.GetCustomAttributes(typeof(WidgetAttribute), true).Length > 0));
                        string controllerShortName = controller.Name.Replace("Controller", "");
                        List<string> actionNames = new List<string>();

                        foreach (MethodInfo action in actions)
                        {
                            WidgetAttribute widgetAttr = (WidgetAttribute)action.GetCustomAttributes(typeof(WidgetAttribute), true)[0];
                            string widgetCat = !string.IsNullOrEmpty(widgetAttr.Category) ? widgetAttr.Category : defaultCategory;
                            var actionName = action.Name;

                            //Supports the AsyncController
                            if (action.Name.EndsWith("async", StringComparison.OrdinalIgnoreCase))
                                actionName = action.Name.Replace("Async", "");

                            var tmplID = widgetCat + "\\" + actionName;

                            //When the Widget had already registered then continue.
                            var registeredDescriptor = descriptorRepository.Find(tmplID);

                            if (registeredDescriptor != null)
                                continue;

                            actionNames.Add("\"" + actionName + "\"");

                            var properties = action.GetCustomAttributes(typeof(PropertyAttribute), true);
                            var defaults = new Dictionary<string, object>();
                            foreach (var pro in properties)
                            {
                                var _pro = ((PropertyAttribute)pro);
                                defaults.Add(_pro.Name, _pro.DefaultValue);
                            }

                            var tmpl = new WidgetTemplate()
                            {
                                ID = tmplID,
                                Name = actionName,
                                Description = widgetAttr.Description,
                                Version = assembly.GetName().Version.ToString(),
                                Author = new WidgetAuthor()
                                {
                                    Name = webOwner.UserName,
                                    Uri = appPath,
                                    Email = webOwner.Email
                                },
                                Defaults = new WidgetDefaults()
                                {
                                    Area = string.IsNullOrEmpty(widgetAttr.Area) ? GetArea(controller) : widgetAttr.Area,
                                    Action = actionName,
                                    Controller = controller.AssemblyQualifiedName,
                                    IconUrl = widgetAttr.IconUrl,
                                    ShowBorder = widgetAttr.ShowBorder,
                                    ShowHeader = widgetAttr.ShowHeader,
                                    Title = widgetAttr.Title,
                                    TitleLinkUrl = widgetAttr.TitleLink
                                },
                                UserPreferences = new List<WidgetUserPreference>()
                            };

                            if (defaults.Count > 0)
                            {
                                foreach (var key in defaults.Keys)
                                {
                                    tmpl.UserPreferences.Add(new WidgetUserPreference()
                                    {
                                        IsReadonly = false,
                                        Name = key,
                                        Type = defaults[key] != null ? defaults[key].GetType().ToString() : (typeof(string)).ToString(),
                                        Value = defaults[key] != null ? defaults[key].ToString() : ""
                                    });
                                }
                            }
                            tmplRepository.Create(tmpl);
                        }
                    }
                }
                catch (Exception e)
                {
                    string msg = e.Message;
                    continue;
                }
            }
        }

        private static string GetArea(Type ctrlType)
        {
            var types = ctrlType.Assembly.GetTypes();
            var areaRegistrationType = types.FirstOrDefault(t =>t.BaseType!=null && t.BaseType.Equals(typeof(AreaRegistration)));
            if (areaRegistrationType == null)
                return "";
            else
            {
                var areaInstance = (AreaRegistration)Activator.CreateInstance(areaRegistrationType);
                return areaInstance.AreaName;
            }
        }
    }
}